home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / prog_gen / freeli10.zip / FREELIB1.ASX < prev    next >
Text File  |  1996-04-20  |  86KB  |  2,874 lines

  1. ~~~C_START
  2. Ideal
  3.  
  4. Extrn       main:near
  5. Public      startup,exit,atexit
  6. Public      TopByte
  7.  
  8. Model Tiny
  9. CodeSeg
  10. P186
  11.  
  12. ;****************** startup() -- Start program
  13.  
  14. Proc        startup
  15.  
  16.             mov al,1                ;Check for 186+
  17.             mov cl,21h
  18.             shl al,cl
  19.             jz p0_badcpu
  20.  
  21.             mov ah,4Ah              ;Modify memory allocation
  22.             mov bx,1000h            ;Keep first 64K
  23.             int 21h                 ;DOS call
  24.  
  25.             mov sp,0FF00h           ;Shift stack down 256 bytes
  26.  
  27.             mov ax,2523h            ;Set null Ctrl-C handler
  28.             mov dx,offset IntRet    ;so that Ctrl-C can't
  29.             int 21h                 ;abort the program
  30.  
  31.             mov ax,3500h            ;Get current Int 0 handler
  32.             int 21h                 ; (divide by zero)
  33.  
  34.             mov [OldInt0],bx        ;Save handler
  35.             mov [OldInt0+2],es
  36.  
  37.             push cs                 ;Restore ES
  38.             pop es
  39.  
  40.             mov ax,2500h            ;Set the divide by zero
  41.             mov dx,offset DivZero   ;handler: now it just
  42.             int 21h                 ;ignores the error
  43.  
  44.             mov ax,0FB00h           ;Initialize dynamic memory
  45.             sub ax,offset TopByte   ;leaving 768 bytes for the
  46.             mov [word TopByte],ax   ;stack (which is at 0FF00h)
  47.             mov [byte TopByte+2],2  ;Initial block is free, last
  48.  
  49.             mov di,0FF00h           ;Parse arguments
  50.             call ParseArgs
  51.  
  52.             call main               ;Call main function
  53.  
  54.             push ax                 ;Terminate with return code
  55.             call exit
  56.  
  57. p0_badcpu:  mov ah,9                ;Print 'Bad CPU' message
  58.             mov dx,offset BadCPUStr
  59.             int 21h
  60.  
  61.             mov ax,4CFFh            ;Return with error 255
  62.             int 21h
  63.  
  64. EndP        startup
  65.  
  66. ;****************** DivZero -- Divide by zero handler
  67.  
  68. Proc        DivZero
  69.  
  70.             push bp                 ;Set up stack frame
  71.             mov bp,sp
  72.             pusha                   ;Save all registers
  73.             push ds
  74.  
  75.             xor cx,cx               ;CX = displacement
  76.  
  77.             mov ds,[bp+4]           ;DS:BX = DIV instruction
  78.             mov bx,[bp+2]
  79.             mov al,[bx+1]           ;AL = AH = ModRM byte
  80.             mov ah,al
  81.  
  82.             and al,0C0h             ;Mask off mode bits
  83.             cmp al,0C0h             ;Mode = 11 (no disp)?
  84.             je DZ_dis0
  85.             cmp al,040h             ;Mode = 01 (1 byte disp)?
  86.             je DZ_dis1
  87.             cmp al,080h             ;Mode = 10 (2 byte disp)?
  88.             je DZ_dis2
  89.             cmp ah,36h              ;Mode = 00.  No disp except
  90.             jne DZ_dis0             ;if R/M = 110 (2 byte disp).
  91.  
  92. DZ_dis2:    inc cx                  ;2 byte displacement
  93. DZ_dis1:    inc cx                  ;1 byte displacement
  94. DZ_dis0:    add cx,2                ;Instruction is two bytes
  95.             add [bp+2],cx           ;Skip past instruction
  96.  
  97. DZ_done:    pop ds                  ;Restore registers
  98.             popa
  99.             pop bp                  ;Delete stack frame
  100. IntRet:     iret                    ;Interrupt return
  101.  
  102. EndP        DivZero
  103.  
  104. ;****************** Internal data
  105.  
  106. BadCPUStr   db 'This program requires an '
  107.             db '80186 or later CPU',13,10,'$'
  108.  
  109. OldInt0     dw 0,0                  ;Old divide-by-zero handler
  110.  
  111. AtExitCnt   dw 0                    ;Exit function count
  112. AtExitTblO  equ 0FF60h              ;Exit function table offset
  113.  
  114. ;****************** exit() -- Terminate program
  115. ;void exit(int retval);
  116.  
  117. Proc        exit
  118.  
  119.             mov ax,2500h            ;Reset the default divide
  120.             mov dx,[OldInt0]        ;by zero handler
  121.             mov ds,[OldInt0+2]
  122.             int 21h
  123.  
  124.             push cs                 ;Restore DS
  125.             pop ds
  126.  
  127.             mov cx,[AtExitCnt]      ;CX = atexit count
  128.             jcxz p1_done            ;No exit functions?
  129.             mov bx,AtExitTblO       ;BX = atexit table
  130.  
  131. p1_loop:    call [word bx]          ;Call function
  132.             inc bx                  ;Advance pointer
  133.             inc bx
  134.             loop p1_loop            ;Loop back
  135.  
  136. p1_done:    pop ax ax               ;Pop arg into AX
  137.             mov ah,4Ch              ;Terminate program
  138.             int 21h                 ;DOS call
  139.  
  140. EndP        exit
  141.  
  142. ;****************** atexit() -- Add exit function
  143. ;int atexit(void *func);
  144.  
  145. func        equ bp+4
  146.  
  147. Proc        atexit
  148.  
  149.             push bp                 ;Set up stack frame
  150.             mov bp,sp
  151.             push bx                 ;Save BX
  152.  
  153.             cmp [word AtExitCnt],16 ;16 functions max
  154.             jae p2_error
  155.  
  156.             mov bx,[AtExitCnt]      ;BX = offset
  157.             add bx,bx
  158.             add bx,AtExitTblO
  159.             mov ax,[func]           ;AX = function
  160.             mov [bx],ax             ;Add function to table
  161.             inc [word AtExitCnt]    ;Increment count
  162.  
  163. p2_done:    pop bx                  ;Restore BX
  164.             pop bp                  ;Delete stack frame
  165.             ret 2                   ;Return
  166.  
  167. p2_error:   xor ax,ax               ;Return 0: failure
  168.             jmp p2_done
  169.  
  170. EndP        atexit
  171.  
  172. ;**************************** ParseArgs() -- internal: Parse arguments
  173.  
  174. Proc        ParseArgs
  175.             ;Supply ES:DI = 256-byte buffer, DS = PSP
  176.             ;Returns CX = number of arguments
  177.             ;the buffer will contain a list of
  178.             ;near offsets to AsciiZ strings
  179.             ;(and the strings themselves)
  180.  
  181.             push es                 ;Save registers
  182.             pusha
  183.  
  184.             mov bx,di               ;BX = buffer
  185.             mov cl,[80h]            ;CX = length of command line
  186.             xor ch,ch               ;which is stored at 80h
  187.  
  188.             push cx                 ;Save CX
  189.             mov si,81h              ;SI = command line
  190.             add di,80h              ;DI = second half of buffer
  191.             push di                 ;Save DI
  192.             rep movsb               ;Move command line out of DTA
  193.             xor al,al               ;Replace the CR at the end
  194.             stosb                   ;with a null
  195.             pop di cx               ;Restore DI, length in CX
  196.             inc cx                  ;Make length include last null
  197.             xor dx,dx               ;Zero argument counter
  198.             mov al,' '              ;AL = space
  199.  
  200. p3_loop:    repe scasb              ;Search for a non-space
  201.             dec di
  202.             inc cx
  203.             cmp [byte es:di],0      ;Is it a null?
  204.             je p3_done
  205.             mov [es:bx],di          ;Store offset in list
  206.             inc bx                  ;Advance pointers
  207.             inc bx
  208.             inc dx
  209.             repne scasb             ;Search for a space
  210.             mov [byte es:di-1],0    ;Replace it by a null
  211.             jmp p3_loop             ;Loop back
  212.  
  213. p3_done:    mov es,dx               ;Tricky -- put count in ES
  214.             popa                    ;Restore general registers
  215.             mov cx,es               ;Count in CX
  216.             pop es                  ;Restore ES
  217.             ret                     ;Return
  218.  
  219. EndP        ParseArgs
  220.  
  221. UDataSeg                            ;Uninit. data seg: dummy
  222.  
  223. Label       TopByte                 ;Top byte of code!
  224.  
  225. End
  226.  
  227. ~~~C_FILES
  228. Ideal
  229.  
  230. Public      fopen,fclose,fsetbuf
  231.  
  232. Model Tiny
  233. CodeSeg
  234. P186
  235.  
  236. ;****************** File Structure . . .
  237.  
  238. ;                   Offset  Size    Description
  239.  
  240. ;                     0     Word    File handle
  241. ;                     2     Word    File mode
  242. ;                     4     Dword   Buffer position in file
  243. ;                     8     Word    Buffer pointer position
  244. ;                     10    Word    Number of bytes in buffer
  245. ;                     12    Word    Size of buffer (N)
  246. ;                     14    Word    Signature 'FI'
  247. ;                     16    N bytes File buffer
  248.  
  249. BUF_SIZ     dw 1024                 ;Buffer size (default 1K)
  250.  
  251. F_MODES     dw 00h,01h              ;0 = open for read
  252.             dw 02h,11h              ;1 = open/create for read/write
  253.             dw 02h,01h              ;2 = open for read/write
  254.             dw 02h,12h              ;3 = create for read/write
  255.  
  256. ;****************** fopen() -- Open a buffered file
  257. ;int fopen(char *fname, int mode);
  258.  
  259. fname       = bp+6
  260. mode        = bp+4
  261.  
  262. Proc        fopen
  263.  
  264.             push bp                 ;Set up stack frame
  265.             mov bp,sp
  266.             push ds si bx cx dx     ;Save registers
  267.  
  268.             mov bx,[mode]           ;BX = mode
  269.             and bx,3                ;Mode mod 3
  270.             shl bx,2
  271.             mov dx,[F_MODES+bx+2]   ;BX:DX = DOS mode
  272.             mov bx,[F_MODES+bx]
  273.  
  274.             mov ax,6C00h            ;Extended open file
  275.             xor cx,cx               ;Normal attribute
  276.             mov si,[fname]          ;SI = name
  277.             int 21h                 ;DOS call
  278.             jc p1_err1              ;Check for errors
  279.  
  280.             mov dx,ax               ;DX = handle
  281.  
  282.             mov ah,48h              ;Allocate memory
  283.             mov bx,[BUF_SIZ]        ;BX = num. of paras
  284.             shr bx,4                ; = (BUF_SIZ / 16) + 1
  285.             inc bx
  286.             int 21h                 ;DOS call
  287.             jc p1_err2              ;Check for errors
  288.  
  289.             mov ds,ax               ;DS = segment
  290.             mov [word 0],dx         ;[word 0] = handle
  291.             mov cx,[mode]
  292.             mov [word 2],cx         ;[word 2] = mode
  293.             xor bx,bx
  294.             mov [word 4],bx         ;[dword 4] = buffer position
  295.             mov [word 6],bx
  296.             mov [word 8],bx         ;[word 8] = buffer pointer
  297.             mov bx,[cs:BUF_SIZ]
  298.             mov [word 12],bx        ;[word 12] = buffer size
  299.             mov [word 14],'FI'      ;[word 14] = 'FI': signature
  300.  
  301.             mov bx,dx               ;BX = handle
  302.             mov ah,3Fh              ;Read file
  303.             mov cx,[cs:BUF_SIZ]     ;BUF_SIZ bytes
  304.             mov dx,16               ;Buffer offset
  305.             int 21h                 ;DOS call
  306.  
  307.             mov [word 10],ax        ;Set byte count
  308.  
  309.             mov ax,ds               ;AX = segment
  310.  
  311. p1_done:    pop dx cx bx si ds      ;Restore registers
  312.             pop bp                  ;Delete stack frame
  313.             ret 4                   ;Return
  314.  
  315. p1_err2:    mov ah,3Eh              ;Out of memory, close file
  316.             mov bx,dx               ;BX = handle
  317.             int 21h                 ;DOS call
  318.  
  319. p1_err1:    xor ax,ax               ;Error, return 0
  320.             jmp p1_done
  321.  
  322. EndP        fopen
  323.  
  324. ;****************** fclose() -- Close a buffered file
  325. ;int fclose(int fptr);
  326.  
  327. fptr        = bp+4
  328.  
  329. Proc        fclose
  330.  
  331.             push bp                 ;Set up stack frame
  332.             mov bp,sp
  333.             push ds es bx cx dx     ;Save registers
  334.  
  335.             mov ds,[fptr]           ;DS = seg of file
  336.             cmp [word 14],'FI'      ;Check for signature
  337.             jne p2_error
  338.  
  339.             mov bx,[word 0]         ;BX = handle
  340.  
  341.             cmp [word 2],0          ;Read only, can't write buffer
  342.             je p2_skip
  343.  
  344.             mov ax,4200h            ;Move file ptr
  345.             mov cx,[word 6]         ;CX:DX = buffer pos
  346.             mov dx,[word 4]
  347.             int 21h                 ;DOS call
  348.  
  349.             mov ah,40h              ;Write file
  350.             mov cx,[word 10]        ;CX = bytes
  351.             mov dx,16               ;Buffer offset
  352.             int 21h                 ;DOS call
  353.  
  354. p2_skip:    mov ah,3Eh              ;Close file
  355.             int 21h                 ;DOS call
  356.  
  357.             mov ah,49h              ;Free memory
  358.             push ds                 ;ES = segment
  359.             pop es
  360.             int 21h                 ;DOS call
  361.  
  362. p2_done:    pop dx cx bx es ds      ;Restore registers
  363.             pop bp                  ;Delete stack frame
  364.             ret 2                   ;Return
  365.  
  366. p2_error:   xor ax,ax               ;Error, return 0
  367.             jmp p2_done
  368.  
  369. EndP        fclose
  370.  
  371. ;****************** fsetbuf() -- Set buffer size (for future use)
  372. ;int fsetbuf(int bsize);
  373.  
  374. bsize       = bp+4
  375.  
  376. Proc        fsetbuf
  377.  
  378.             push bp                 ;Set up stack frame
  379.             mov bp,sp
  380.  
  381.             mov ax,[bsize]          ;AX = size
  382.             and ax,7FF0h            ;Put it in range
  383.             cmp ax,128
  384.             jb $+5
  385.             mov ax,128
  386.             mov [BUF_SIZ],ax        ;Set buffer size
  387.  
  388.             pop bp                  ;Delete stack frame
  389.             ret 2                   ;Return
  390.  
  391. EndP        fsetbuf
  392.  
  393. End
  394.  
  395. ~~~C_FPUTC
  396. Ideal
  397.  
  398. Public      fputc
  399.  
  400. Model Tiny
  401. CodeSeg
  402. P186
  403.  
  404. ;****************** fputc() -- Put char to buffered file
  405. ;int fputc(int fptr, int chr);
  406.  
  407. fptr        = bp+6
  408. chr         = bp+4
  409.  
  410. Proc        fputc
  411.  
  412.             push bp                 ;Set up stack frame
  413.             mov bp,sp
  414.             push ds si bx cx dx     ;Save registers
  415.  
  416.             mov ds,[fptr]           ;DS = seg of file
  417.             cmp [word 14],'FI'      ;Check for signature
  418.             jne p1_error
  419.  
  420.             mov bx,[word 0]         ;BX = handle
  421.  
  422.             cmp [word 2],0          ;Read only, can't put char
  423.             je p1_error
  424.  
  425.             mov si,[word 8]         ;SI = pointer pos
  426.             cmp si,[word 12]        ;Filled buffer?
  427.             jb p1_write             ;Jump if not
  428.  
  429.             mov ax,4200h            ;Move file ptr
  430.             mov cx,[word 6]         ;CX:DX = buffer pos
  431.             mov dx,[word 4]
  432.             int 21h                 ;DOS call
  433.  
  434.             mov ah,40h              ;Write file
  435.             mov cx,[word 12]        ;CX = bytes
  436.             mov dx,16               ;Buffer offset
  437.             int 21h                 ;DOS call
  438.  
  439.             mov ah,3Fh              ;Read file, same data...
  440.             int 21h                 ;DOS call
  441.             mov [word 10],ax        ;Set byte count
  442.  
  443.             xor si,si
  444.             add [word 4],cx         ;Advance buffer position
  445.             adc [word 6],si
  446.             mov [word 8],si         ;Pointer pos = 0
  447.  
  448. p1_write:   mov al,[chr]            ;AX = char
  449.             xor ah,ah
  450.             mov [16+si],al          ;Put char in buffer
  451.             inc si                  ;Advance pointer
  452.             mov [word 8],si
  453.             cmp si,[word 10]        ;Hit last byte?
  454.             jna p1_done
  455.  
  456.             inc [word 10]           ;Advance byte count
  457.  
  458. p1_done:    pop dx cx bx si ds      ;Restore registers
  459.             pop bp                  ;Delete stack frame
  460.             ret 4                   ;Return
  461.  
  462. p1_error:   mov ax,-1               ;Error, return EOF
  463.             jmp p1_done
  464.  
  465. EndP        fputc
  466.  
  467. End
  468.  
  469. ~~~C_FGETC
  470. Ideal
  471.  
  472. Public      fgetc
  473.  
  474. Model Tiny
  475. CodeSeg
  476. P186
  477.  
  478. ;****************** fgetc() -- Get char from buffered file
  479. ;int fgetc(int fptr);
  480.  
  481. fptr        = bp+4
  482.  
  483. Proc        fgetc
  484.  
  485.             push bp                 ;Set up stack frame
  486.             mov bp,sp
  487.             push ds si bx cx dx     ;Save registers
  488.  
  489.             mov ds,[fptr]           ;DS = seg of file
  490.             cmp [word 14],'FI'      ;Check for signature
  491.             jne p1_error
  492.  
  493.             mov bx,[word 0]         ;BX = handle
  494.  
  495.             mov si,[word 8]         ;SI = pointer pos
  496.             mov cx,[word 12]        ;CX = buffer size
  497.             cmp si,cx               ;End of buffer?
  498.             jb p1_read              ;Jump if not
  499.  
  500.             xor si,si
  501.             add [word 4],cx         ;Advance buffer position
  502.             adc [word 6],si
  503.             mov [word 2],si         ;Pointer pos = 0
  504.  
  505.             mov ax,4200h            ;Move file ptr
  506.             mov cx,[word 6]         ;CX:DX = buffer pos
  507.             mov dx,[word 4]
  508.             int 21h                 ;DOS call
  509.  
  510.             mov ah,3Fh              ;Read file
  511.             mov cx,[word 12]        ;CX = bytes
  512.             mov dx,16               ;Buffer offset
  513.             int 21h                 ;DOS call
  514.             mov [word 10],ax        ;Set byte count
  515.  
  516. p1_read:    cmp si,[word 10]        ;Hit last byte?
  517.             jae p1_error
  518.  
  519.             mov al,[16+si]          ;Get char from buffer
  520.             xor ah,ah
  521.             inc si                  ;Advance pointer
  522.             mov [word 8],si
  523.  
  524. p1_done:    pop dx cx bx si ds      ;Restore registers
  525.             pop bp                  ;Delete stack frame
  526.             ret 2                   ;Return
  527.  
  528. p1_error:   mov ax,-1               ;Error, return EOF
  529.             jmp p1_done
  530.  
  531. EndP        fgetc
  532.  
  533. End
  534.  
  535. ~~~C_FSEEK
  536. Ideal
  537.  
  538. Public      fseek,ftell
  539.  
  540. Model Tiny
  541. CodeSeg
  542. P186
  543.  
  544. ;****************** fseek() -- Seek to position in buffered file
  545. ;int fseek(int fptr, long pos, int cmd);
  546.  
  547. fptr        = bp+10
  548. pos         = bp+6
  549. cmd         = bp+4
  550.  
  551. Proc        fseek
  552.  
  553.             push bp                 ;Set up stack frame
  554.             mov bp,sp
  555.             push ds bx cx dx        ;Save registers
  556.  
  557.             mov ds,[fptr]           ;DS = seg of file
  558.             cmp [word 14],'FI'      ;Check for signature
  559.             jne p1_error
  560.  
  561.             mov bx,[word 0]         ;BX = handle
  562.  
  563.             cmp [word 2],0          ;Read only, can't write buffer
  564.             je p1_seek
  565.  
  566.             mov ax,4200h            ;Move file ptr
  567.             mov cx,[word 6]         ;CX:DX = buffer pos
  568.             mov dx,[word 4]
  569.             int 21h                 ;DOS call
  570.  
  571.             mov ah,40h              ;Write file
  572.             mov cx,[word 10]        ;CX = bytes
  573.             mov dx,16               ;Buffer offset
  574.             int 21h                 ;DOS call
  575.  
  576. p1_seek:    mov ax,4200h            ;Move file ptr
  577.             mov cx,[word 6]         ;CX:DX = current pos
  578.             mov dx,[word 4]         ; = buffer pos + pointer
  579.             add dx,[word 8]
  580.             adc cx,0
  581.             int 21h                 ;DOS call
  582.  
  583.             mov ah,42h              ;Move file ptr
  584.             mov al,[cmd]            ;AL = command
  585.             mov cx,[pos+2]          ;CX:DX = new pos
  586.             mov dx,[pos]
  587.             int 21h                 ;DOS call
  588.  
  589.             mov [word 6],dx         ;Save position
  590.             mov [word 4],ax
  591.  
  592.             mov ah,3Fh              ;Read file
  593.             mov cx,[word 12]        ;CX = bytes
  594.             mov dx,16               ;Buffer offset
  595.             int 21h                 ;DOS call
  596.  
  597.             mov [word 10],ax        ;Set byte count
  598.             mov [word 8],0          ;Pointer = 0
  599.             mov ax,1                ;return 1: success
  600.  
  601. p1_done:    pop dx cx bx ds         ;Restore registers
  602.             pop bp                  ;Delete stack frame
  603.             ret 8                   ;Return
  604.  
  605. p1_error:   xor ax,ax               ;Error, return 0
  606.             jmp p1_done
  607.  
  608. EndP        fseek
  609.  
  610. ;****************** ftell() -- Return pointer in buffered file
  611. ;long ftell(int fptr);
  612.  
  613. fptr        = bp+4
  614.  
  615. Proc        ftell
  616.  
  617.             push bp                 ;Set up stack frame
  618.             mov bp,sp
  619.             push ds                 ;Save registers
  620.  
  621.             mov ds,[fptr]           ;DS = seg of file
  622.             cmp [word 14],'FI'      ;Check for signature
  623.             jne p2_error
  624.  
  625.             mov dx,[word 6]         ;DX:AX = current pos
  626.             mov ax,[word 4]         ; = buffer pos + pointer
  627.             add ax,[word 8]
  628.             adc dx,0
  629.  
  630. p2_done:    pop ds                  ;Restore registers
  631.             pop bp                  ;Delete stack frame
  632.             ret 2                   ;Return
  633.  
  634. p2_error:   xor ax,ax               ;Error, return 0
  635.             xor dx,dx
  636.             jmp p2_done
  637.  
  638. EndP        ftell
  639.  
  640. End
  641.  
  642. ~~~C_FREAD
  643. Ideal
  644.  
  645. Extrn       fgetc:near
  646. Public      fread
  647.  
  648. Model Tiny
  649. CodeSeg
  650. P186
  651.  
  652. ;****************** fread() -- Read block from buffered file
  653. ;int fread(int fptr, int nbytes, void *buf);
  654.  
  655. fptr        = bp+8
  656. nbytes      = bp+6
  657. buf         = bp+4
  658.  
  659. Proc        fread
  660.  
  661.             push bp                 ;Set up stack frame
  662.             mov bp,sp
  663.             push bx cx di           ;Save registers
  664.  
  665.             mov bx,[fptr]           ;BX = file ptr
  666.             mov cx,[nbytes]         ;CX = num. of bytes
  667.             mov di,[buf]            ;DI = buffer ptr
  668.             jcxz p1_done            ;Zero bytes, do nothing
  669.  
  670. p1_loop:    push bx                 ;Get char
  671.             call fgetc
  672.             test ax,ax              ;Check for errors
  673.             jl p1_done
  674.             mov [di],al             ;Store byte
  675.             inc di
  676.             loop p1_loop            ;Loop back
  677.  
  678. p1_done:    sub di,[buf]            ;AX = byte count
  679.             mov ax,di
  680.  
  681.             pop di cx bx            ;Restore registers
  682.             pop bp                  ;Delete stack frame
  683.             ret 6                   ;Return
  684.  
  685. EndP        fread
  686.  
  687. End
  688.  
  689. ~~~C_FWRITE
  690. Ideal
  691.  
  692. Extrn       fputc:near
  693. Public      fwrite
  694.  
  695. Model Tiny
  696. CodeSeg
  697. P186
  698.  
  699. ;****************** fwrite() -- Write block to buffered file
  700. ;int fwrite(int fptr, int nbytes, void *buf);
  701.  
  702. fptr        = bp+8
  703. nbytes      = bp+6
  704. buf         = bp+4
  705.  
  706. Proc        fwrite
  707.  
  708.             push bp                 ;Set up stack frame
  709.             mov bp,sp
  710.             push bx cx si           ;Save registers
  711.  
  712.             mov bx,[fptr]           ;BX = file ptr
  713.             mov cx,[nbytes]         ;CX = num. of bytes
  714.             mov si,[buf]            ;SI = buffer ptr
  715.             mov ax,1                ;Fixup for zero check
  716.             jcxz p1_done            ;Zero bytes, do nothing
  717.  
  718. p1_loop:    lodsb                   ;Load byte
  719.             push bx ax              ;Write char
  720.             call fputc
  721.             test ax,ax              ;Check for errors
  722.             jl p1_done
  723.             loop p1_loop            ;Loop back
  724.  
  725. p1_done:    sub si,[buf]            ;AX = byte count
  726.             dec ax                  ;Subtract 1 if error
  727.             sbb si,0
  728.             mov ax,si
  729.  
  730.             pop si cx bx            ;Restore registers
  731.             pop bp                  ;Delete stack frame
  732.             ret 6                   ;Return
  733.  
  734. EndP        fwrite
  735.  
  736. End
  737.  
  738. ~~~C_FTRUNC
  739. Ideal
  740.  
  741. Public      ftrunc
  742.  
  743. Model Tiny
  744. CodeSeg
  745. P186
  746.  
  747. ;****************** ftrunc() -- Truncate buffered file at current position
  748. ;int ftrunc(int fptr);
  749.  
  750. fptr        = bp+4
  751.  
  752. Proc        ftrunc
  753.  
  754.             push bp                 ;Set up stack frame
  755.             mov bp,sp
  756.             push ds bx cx dx        ;Save registers
  757.  
  758.             mov ds,[fptr]           ;DS = seg of file
  759.             cmp [word 14],'FI'      ;Check for signature
  760.             jne p1_error
  761.  
  762.             cmp [word 2],0          ;Read only, can't truncate
  763.             je p1_error
  764.  
  765.             mov bx,[word 0]         ;BX = handle
  766.  
  767.             mov ax,4200h            ;Move file ptr
  768.             mov cx,[word 6]         ;CX:DX = current pos
  769.             mov dx,[word 4]         ; = buffer pos + pointer
  770.             add dx,[word 8]
  771.             adc cx,0
  772.             int 21h                 ;DOS call
  773.  
  774.             mov ah,40h              ;Write 0 bytes to file
  775.             xor cx,cx               ;this truncates the file
  776.             int 21h
  777.  
  778.             mov ax,[word 8]         ;Now, byte count = pointer + 1
  779.             inc ax
  780.             mov [word 10],ax
  781.             mov ax,1                ;return 1: success
  782.  
  783. p1_done:    pop dx cx bx ds         ;Restore registers
  784.             pop bp                  ;Delete stack frame
  785.             ret 2                   ;Return
  786.  
  787. p1_error:   xor ax,ax               ;Error, return 0
  788.             jmp p1_done
  789.  
  790. EndP        ftrunc
  791.  
  792. End
  793.  
  794. ~~~C_DELMOV
  795. Ideal
  796.  
  797. Public      fdel,fmove
  798.  
  799. Model Tiny
  800. CodeSeg
  801. P186
  802.  
  803. ;****************** fdel() -- Delete a file
  804. ;int fdel(char *strp);
  805.  
  806. strp        equ bp+4
  807.  
  808. Proc        fdel
  809.  
  810.             push bp                 ;Set up stack frame
  811.             mov bp,sp
  812.             push dx                 ;Save DX
  813.  
  814.             mov ah,41h              ;Delete file
  815.             mov dx,[strp]           ;DX = string pointer
  816.             int 21h                 ;DOS call
  817.  
  818.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  819.             cbw                     ;AX = 1 if ok, 0 if error
  820.             inc ax
  821.  
  822.             pop dx                  ;Restore DX
  823.             pop bp                  ;Delete stack frame
  824.             ret 2                   ;Return
  825.  
  826. EndP        fdel
  827.  
  828. ;****************** fmove() -- Move and/or rename a file
  829. ;int fmove(char *str1, char *str2);
  830.  
  831. str1        equ bp+6
  832. str2        equ bp+4
  833.  
  834. Proc        fmove
  835.  
  836.             push bp                 ;Set up stack frame
  837.             mov bp,sp
  838.             push es dx di           ;Save registers
  839.  
  840.             mov ah,56h              ;Move file
  841.             mov dx,[str1]           ;DX = old name
  842.             push ds                 ;ES = DS
  843.             pop es
  844.             mov di,[str2]           ;ES:DI = new name
  845.             int 21h                 ;DOS call
  846.  
  847.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  848.             cbw                     ;AX = 1 if ok, 0 if error
  849.             inc ax
  850.  
  851.             pop di dx es            ;Restore registers
  852.             pop bp                  ;Delete stack frame
  853.             ret 4                   ;Return
  854.  
  855. EndP        fmove
  856.  
  857. End
  858.  
  859. ~~~C_DIRECT
  860. Ideal
  861.  
  862. Public      getdir,setdir,mkdir,rmdir
  863.  
  864. Model Tiny
  865. CodeSeg
  866. P186
  867.  
  868. ;****************** getdir() -- Get current directory
  869. ;void getdir(char *strp);
  870.  
  871. strp        equ bp+4
  872.  
  873. Proc        getdir
  874.  
  875.             push bp                 ;Set up stack frame
  876.             mov bp,sp
  877.             pusha                   ;Save registers
  878.  
  879.             mov ah,19h              ;Get current drive
  880.             int 21h                 ;DOS call
  881.  
  882.             mov dl,al               ;DL = drive
  883.             mov ah,47h              ;Get current directory
  884.             mov si,[strp]           ;SI = string pointer
  885.             mov [byte si],'\'       ;Add leading slash
  886.             inc si
  887.             int 21h                 ;DOS call
  888.  
  889.             popa                    ;Restore registers
  890.             pop bp                  ;Delete stack frame
  891.             ret 2                   ;Return
  892.  
  893. EndP        getdir
  894.  
  895. ;****************** DIRcall -- Internal: used by setdir,mkdir,rmdir
  896. ;void DIRcall(void);
  897.  
  898. strp        equ bp+4
  899.  
  900. Proc        DIRcall
  901.  
  902.             push dx                 ;Save DX
  903.             mov dx,[strp]           ;DX = string pointer
  904.             int 21h                 ;DOS call
  905.  
  906.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  907.             cbw                     ;AX = 1 if ok, 0 if error
  908.             inc ax
  909.  
  910.             pop dx                  ;Restore DX
  911.             ret                     ;Return
  912.  
  913. EndP        DIRcall
  914.  
  915. ;****************** setdir() -- Set current directory
  916. ;int setdir(char *strp);
  917.  
  918. strp        equ bp+4
  919.  
  920. Proc        setdir
  921.  
  922.             push bp                 ;Set up stack frame
  923.             mov bp,sp
  924.  
  925.             mov ah,3Bh              ;Set current directory
  926.             call DIRcall            ;Directory call
  927.  
  928.             pop bp                  ;Delete stack frame
  929.             ret 2                   ;Return
  930.  
  931. EndP        setdir
  932.  
  933. ;****************** mkdir() -- Create a directory
  934. ;int mkdir(char *strp);
  935.  
  936. strp        equ bp+4
  937.  
  938. Proc        mkdir
  939.  
  940.             push bp                 ;Set up stack frame
  941.             mov bp,sp
  942.  
  943.             mov ah,39h              ;Create directory
  944.             call DIRcall            ;Directory call
  945.  
  946.             pop bp                  ;Delete stack frame
  947.             ret 2                   ;Return
  948.  
  949. EndP        mkdir
  950.  
  951. ;****************** rmdir() -- Remove a directory
  952. ;int rmdir(char *strp);
  953.  
  954. strp        equ bp+4
  955.  
  956. Proc        rmdir
  957.  
  958.             push bp                 ;Set up stack frame
  959.             mov bp,sp
  960.  
  961.             mov ah,3Ah              ;Remove directory
  962.             call DIRcall            ;Directory call
  963.  
  964.             pop bp                  ;Delete stack frame
  965.             ret 2                   ;Return
  966.  
  967. EndP        rmdir
  968.  
  969. End
  970.  
  971. ~~~C_DRIVE
  972. Ideal
  973.  
  974. Public      getdrive,setdrive
  975.  
  976. Model Tiny
  977. CodeSeg
  978. P186
  979.  
  980. ;****************** getdrive() -- Get current drive
  981. ;int getdrive(void);
  982.  
  983. Proc        getdrive
  984.  
  985.             mov ah,19h              ;Get current drive
  986.             int 21h
  987.             xor ah,ah               ;Zero AH
  988.             ret                     ;Return
  989.  
  990. EndP        getdrive
  991.  
  992. ;****************** setdrive() -- set current drive
  993. ;void setdrive(int drnum);
  994.  
  995. drnum       equ bp+4
  996.  
  997. Proc        setdrive
  998.  
  999.             push bp                 ;Set up stack frame
  1000.             mov bp,sp
  1001.             pusha                   ;Save registers
  1002.  
  1003.             mov ah,0Eh              ;Set current drive
  1004.             mov dl,[drnum]          ;DL = drive number
  1005.             int 21h
  1006.  
  1007.             popa                    ;Restore registers
  1008.             pop bp                  ;Delete stack frame
  1009.             ret 2                   ;Return
  1010.  
  1011. EndP        setdrive
  1012.  
  1013. End
  1014.  
  1015. ~~~C_DFREE
  1016. Ideal
  1017.  
  1018. Public      getdfree
  1019.  
  1020. Model Tiny
  1021. CodeSeg
  1022. P186
  1023.  
  1024. ;****************** getdfree() -- Return amount of free disk space
  1025. ;long getdfree(int drive);
  1026.  
  1027. drive       equ bp+4
  1028.  
  1029. Proc        getdfree
  1030.  
  1031.             push bp                 ;Set up stack frame
  1032.             mov bp,sp
  1033.             push bx cx              ;Save registers
  1034.  
  1035.             mov dl,[drive]          ;DL = drive
  1036.             mov ah,36h              ;Get free disk space
  1037.             int 21h
  1038.  
  1039.             cbw                     ;DX:AX = AX
  1040.             cmp ax,-1               ;Invalid, return -1
  1041.             je p1_done
  1042.  
  1043.             mul cx                  ;DX:AX = free disk space
  1044.             mul bx                  ; = bytes/sector * sectors/a-unit
  1045.                                     ; * free a-units (allocation units)
  1046.  
  1047. p1_done:    pop cx bx               ;Restore registers
  1048.             pop bp                  ;Delete stack frame
  1049.             ret                     ;Return
  1050.  
  1051. EndP        getdfree
  1052.  
  1053. End
  1054.  
  1055. ~~~C_EXEC
  1056. Ideal
  1057.  
  1058. Extrn       allocmem:near,freemem:near
  1059. Public      exec
  1060.  
  1061. Model Tiny
  1062. CodeSeg
  1063. P186
  1064.  
  1065. ;****************** exec() -- Execute program
  1066. ;int exec(char *prog, char *cmdline);
  1067.  
  1068. prog        equ bp+6
  1069. cmdline     equ bp+4
  1070.  
  1071. Proc        exec
  1072.  
  1073.             push bp                 ;Set up stack frame
  1074.             mov bp,sp
  1075.             push ds es              ;Save all registers
  1076.             pusha
  1077.  
  1078.             push 128                ;Allocate memory for
  1079.             call allocmem           ;the cmdline buffer
  1080.             test ax,ax              ;Out of memory?
  1081.             je p1_done
  1082.             mov bx,ax               ;Pointer in BX
  1083.  
  1084.             mov si,[prog]           ;SI = program specification
  1085.  
  1086. p1_loop1:   lodsb                   ;Skip past initial spaces
  1087.             cmp al,' '
  1088.             je p1_loop1
  1089.             dec si
  1090.             push si                 ;Save prog string offset
  1091.  
  1092.             mov si,[cmdline]        ;SI = command line
  1093.             mov di,bx               ;DI = string buffer
  1094.             inc di
  1095.             mov cx,126              ;CX = 126
  1096.  
  1097. p1_loop3:   lodsb                   ;Copy the string and
  1098.             test al,al              ;count the chars
  1099.             je p1_cont
  1100.             stosb
  1101.             loop p1_loop3
  1102.  
  1103. p1_cont:    neg cx                  ;CX = char count
  1104.             add cx,126
  1105.             mov [bx],cl             ;Store count
  1106.             mov al,13               ;Store a CR
  1107.             stosb
  1108.  
  1109.             mov ax,[2Eh]            ;word 0 = environment
  1110.             mov [ParBlock],ax
  1111.             mov [ParBlock+2],bx     ;word 2 = command line
  1112.             mov [ParBlock+4],cs     ;word 4 = CS
  1113.             mov [ParBlock+6],5Ch    ;word 6 = 5Ch
  1114.             mov [ParBlock+8],cs     ;word 8 = CS
  1115.             mov [ParBlock+10],6Ch   ;word 10 = 6Ch
  1116.             mov [ParBlock+12],cs    ;word 12 = CS
  1117.  
  1118.             push bx                 ;Save memory pointer
  1119.  
  1120.             push ds                 ;ES:BX = parameter block
  1121.             pop es
  1122.             mov bx,offset ParBlock
  1123.             pop dx                  ;DX = program specification
  1124.             mov ax,4B00h            ;DOS EXEC function
  1125.  
  1126.             mov [StackBuf],ss       ;Save stack pointer
  1127.             mov [StackBuf+2],sp
  1128.  
  1129.             int 21h                 ;Execute program
  1130.  
  1131.             mov ss,[cs:StackBuf]    ;Restore stack pointer
  1132.             mov sp,[cs:StackBuf+2]
  1133.  
  1134.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  1135.             cbw                     ;AX = 1 if ok, 0 if error
  1136.             inc ax
  1137.  
  1138.             call freemem            ;Free the memory (BX is still pushed)
  1139.  
  1140. p1_done:    mov es,ax               ;Save AX in ES
  1141.             popa                    ;Restore general registers
  1142.             mov ax,es               ;Restore AX
  1143.             pop es ds               ;Restore segment registers
  1144.             pop bp                  ;Delete stack frame
  1145.             ret 4                   ;Return
  1146.  
  1147. StackBuf    dw 0,0                  ;Save area for SS:SP
  1148.  
  1149. ParBlock    dw 7 dup(0)             ;EXEC parameter block
  1150.  
  1151. EndP        exec
  1152.  
  1153. End
  1154.  
  1155. ~~~C_MEMORY
  1156. Ideal
  1157.  
  1158. Extrn       TopByte:Word
  1159. Public      allocmem,freemem,getmfree
  1160.  
  1161. Model Tiny
  1162. P186
  1163. CodeSeg
  1164.  
  1165. ;****************** allocmem() -- Allocate memory
  1166. ;void *allocmem(unsigned nbytes);
  1167.  
  1168. nbytes      equ bp+4
  1169.  
  1170. Proc        allocmem
  1171.  
  1172.             push bp                 ;Set up stack frame
  1173.             mov bp,sp
  1174.             push bx cx dx si        ;Save registers
  1175.  
  1176.             mov dx,[bp+4]           ;DX = num. of bytes + 3
  1177.             add dx,3
  1178.             mov bx,offset TopByte   ;BX = first MCB
  1179.  
  1180. p1_loop:    mov cl,[bx+2]           ;CX = flag byte
  1181.             test cl,1               ;Not free, loop
  1182.             jnz p1_lb
  1183.             mov ax,[bx]             ;AX = size
  1184.             cmp ax,dx               ;Big enough?
  1185.             ja p1_gotit
  1186.  
  1187. p1_lb:      test cl,2               ;Last block?
  1188.             jnz p1_nope             ;Out of memory
  1189.             add bx,[bx]             ;Next block
  1190.             jmp p1_loop             ;Loop back
  1191.  
  1192. p1_gotit:   sub ax,3                ;Check for snug fit,
  1193.             cmp ax,dx               ;that is, too little
  1194.             jbe p1_snug             ;excess to split it
  1195.  
  1196.             sub ax,dx               ;AX = excess
  1197.             add ax,3
  1198.  
  1199.             mov si,bx               ;SI = split point
  1200.             add si,dx
  1201.             mov [si],ax             ;Set size of excess block
  1202.             mov [si+2],cl           ;Set flags to original values
  1203.  
  1204.             mov [bx],dx             ;Set size of present block
  1205.             mov [byte bx+2],1       ;Set flags: allocated, not last
  1206.             jmp p1_finish
  1207.  
  1208. p1_snug:    or [byte bx+2],1        ;Set allocated flag
  1209.  
  1210. p1_finish:  mov ax,bx               ;AX = offset of memory block
  1211.             add ax,3
  1212.  
  1213. p1_done:    pop si dx cx bx         ;Restore registers
  1214.             pop bp                  ;Delete stack frame
  1215.             ret 2                   ;Return
  1216.  
  1217. p1_nope:    xor ax,ax               ;Return null pointer
  1218.             jmp p1_done
  1219.  
  1220. EndP        allocmem
  1221.  
  1222. ;****************** freemem() -- Free memory
  1223. ;void freemem(void *ptr);
  1224.  
  1225. ptr         equ bp+4
  1226.  
  1227. Proc        freemem
  1228.  
  1229.             push bp                 ;Set up stack frame
  1230.             mov bp,sp
  1231.             pusha                   ;Save registers
  1232.  
  1233.             mov dx,[ptr]            ;DX = pointer
  1234.             sub dx,3                ;Point to MCB
  1235.             mov bx,offset TopByte   ;BX = first MCB
  1236.             xor si,si               ;Zero previous ptr.
  1237.  
  1238. p2_loop:    cmp bx,dx               ;Found it?
  1239.             je p2_gotit
  1240.  
  1241.             test [byte bx+2],2      ;Last block?
  1242.             jnz p2_done
  1243.             mov si,bx               ;Save block
  1244.             add bx,[bx]             ;Next block
  1245.             jmp p2_loop             ;Loop back
  1246.  
  1247. p2_gotit:   mov di,bx               ;DI = next block
  1248.             add di,[bx]
  1249.  
  1250.             test [byte bx+2],2      ;Next block allocated
  1251.             jnz p2_cont1            ;or nonexistent, can't
  1252.             mov cl,[di+2]           ;merge with it
  1253.             test cl,1
  1254.             jnz p2_done
  1255.  
  1256.             mov ax,[di]             ;Merge blocks: sum sizes,
  1257.             add [bx],ax             ;set flags of second one
  1258.             mov [bx+2],cl
  1259.  
  1260. p2_cont1:   and [byte bx+2],0FEh    ;Reset allocated flag
  1261.  
  1262.             test si,si              ;Prev. block allocated
  1263.             jz p2_done              ;or nonexistent, can't
  1264.             mov cl,[si+2]           ;merge with it
  1265.             test cl,1
  1266.             jnz p2_done
  1267.  
  1268.             mov ax,[bx]            ;Merge blocks: sum sizes,
  1269.             add [si],ax            ;set flags of second one
  1270.             mov cl,[bx+2]
  1271.             mov [si],cl
  1272.  
  1273. p2_done:    popa                    ;Restore registers
  1274.             pop bp                  ;Delete stack frame
  1275.             ret 2                   ;Return
  1276.  
  1277. EndP        freemem
  1278.  
  1279. ;****************** getmfree() -- Return largest free memory block
  1280. ;unsigned getmfree(void);
  1281.  
  1282. ptr         equ bp+4
  1283.  
  1284. Proc        getmfree
  1285.  
  1286.             push bp                 ;Set up stack frame
  1287.             mov bp,sp
  1288.             push bx                 ;Save registers
  1289.  
  1290.             mov bx,offset TopByte   ;BX = first MCB
  1291.             xor ax,ax               ;Zero counter
  1292.  
  1293. p3_loop:    test [byte bx+2],1      ;Not free, skip
  1294.             jnz p3_skip
  1295.             cmp ax,[bx]             ;Biggest so far?
  1296.             jae p3_skip
  1297.             mov ax,[bx]             ;Save largest block
  1298.  
  1299. p3_skip:    test [byte bx+2],2      ;Last block?
  1300.             jnz p3_done
  1301.             add bx,[bx]             ;Next block
  1302.             jmp p3_loop             ;Loop back
  1303.  
  1304. p3_done:    sub ax,3                ;Adjust to true size
  1305.             pop bx                  ;Restore registers
  1306.             pop bp                  ;Delete stack frame
  1307.             ret                     ;Return
  1308.  
  1309. EndP        getmfree
  1310.  
  1311. End
  1312.  
  1313. ~~~C_FARMEM
  1314. Ideal
  1315.  
  1316. Public      faralloc,farfree,getfarfree
  1317.  
  1318. Model Tiny
  1319. P186
  1320. CodeSeg
  1321.  
  1322. ;****************** faralloc() -- Allocate far memory
  1323. ;int faralloc(int nparas);
  1324.  
  1325. nparas      equ bp+4
  1326.  
  1327. Proc        faralloc
  1328.  
  1329.             push bp                 ;Set up stack frame
  1330.             mov bp,sp
  1331.             push bx                 ;Save BX
  1332.  
  1333.             mov ah,48h              ;Allocate memory
  1334.             mov bx,[nparas]         ;BX = paras
  1335.             int 21h                 ;DOS call
  1336.  
  1337.             jnc $+4                 ;No error, return pointer
  1338.             xor ax,ax               ;Error, return 0
  1339.  
  1340.             pop bx                  ;Restore BX
  1341.             pop bp                  ;Delete stack frame
  1342.             ret 2                   ;Return
  1343.  
  1344. EndP        faralloc
  1345.  
  1346. ;****************** farfree() -- Free far memory
  1347. ;void farfree(int ptr);
  1348.  
  1349. ptr         equ bp+4
  1350.  
  1351. Proc        farfree
  1352.  
  1353.             push bp                 ;Set up stack frame
  1354.             mov bp,sp
  1355.             push es ax              ;Save registers
  1356.  
  1357.             mov ah,4Ah              ;Free memory
  1358.             mov es,[ptr]            ;ES = pointer
  1359.             int 21h                 ;DOS call
  1360.  
  1361.             pop ax es               ;Restore registers
  1362.             pop bp                  ;Delete stack frame
  1363.             ret 2                   ;Return
  1364.  
  1365. EndP        farfree
  1366.  
  1367. ;****************** getfarfree() -- Return largest free far memory block
  1368. ;unsigned getfarfree(void);
  1369.  
  1370. ptr         equ bp+4
  1371.  
  1372. Proc        getfarfree
  1373.  
  1374.             push bp                 ;Set up stack frame
  1375.             mov bp,sp
  1376.             push bx                 ;Save registers
  1377.  
  1378.             mov ah,48h              ;Allocate memory
  1379.             mov bx,-1               ;-1 is invalid
  1380.             int 21h                 ;DOS call (returns an error)
  1381.             mov ax,bx               ;AX = size of largest free block
  1382.  
  1383.             pop bx                  ;Restore registers
  1384.             pop bp                  ;Delete stack frame
  1385.             ret                     ;Return
  1386.  
  1387. EndP        getfarfree
  1388.  
  1389. End
  1390.  
  1391. ~~~C_ATOI
  1392. Ideal
  1393.  
  1394. Public      atoi,atol
  1395.  
  1396. Model Tiny
  1397. CodeSeg
  1398. P186
  1399.  
  1400. ;****************** atoi() -- Convert string to int
  1401. ;int atoi(char *strp);
  1402.  
  1403. strp        equ bp+4
  1404.  
  1405. Proc        atoi
  1406.  
  1407.             push bp                 ;Set up stack frame
  1408.             mov bp,sp
  1409.  
  1410.             push dx [strp]          ;Save DX, call atol
  1411.             call atol
  1412.  
  1413.             pop dx                  ;Restore DX
  1414.             pop bp                  ;Delete stack frame
  1415.             ret 2                   ;Return
  1416.  
  1417. EndP        atoi
  1418.  
  1419. ;****************** atol() -- Convert string to long
  1420. ;long atol(char *strp);
  1421.  
  1422. strp        equ bp+4
  1423.  
  1424. Proc        atol
  1425.  
  1426.             push bp                 ;Set up stack frame
  1427.             mov bp,sp
  1428.             push bx cx si di bp     ;Save registers
  1429.  
  1430.             mov si,[strp]           ;SI = string
  1431.  
  1432.             xor ax,ax               ;DX:AX = 0
  1433.             xor bh,bh               ;BH = 0
  1434.             cwd
  1435.             mov cx,10               ;CX = 10
  1436.  
  1437. p1_ploop:   mov bl,[si]             ;Load char
  1438.             inc si
  1439.             cmp bl,' '              ;Loop while char is space
  1440.             je p1_ploop             ;(20h, or 09h thru 0Dh)
  1441.             cmp bl,9
  1442.             jna p1_cont
  1443.             cmp bl,13
  1444.             jbe p1_ploop
  1445.  
  1446. p1_cont:    xor bp,bp               ;BP = 0
  1447.             cmp bl,'+'              ;If char = '+', ignore
  1448.             je p1_loop
  1449.             cmp bl,'-'              ;If char <> '-', keep it
  1450.             jne p1_skip
  1451.             inc bp                  ;Set negative flag
  1452.  
  1453. p1_loop:    mov bl,[si]             ;Load char
  1454.             inc si
  1455.  
  1456. p1_skip:    cmp bl,'9'              ;Not a digit, finish
  1457.             ja p1_finish
  1458.             sub bl,'0'
  1459.             jc p1_finish
  1460.  
  1461.             mul cx                  ;Multiply by 10
  1462.             add ax,bx               ;Add in digit...
  1463.             adc dl,dh
  1464.             jz p1_loop              ;Not a long yet, loop
  1465.             jmp p1_lload            ;Go into long loop
  1466.  
  1467. p1_lloop:   mov di,dx               ;DI = old hi word
  1468.             mov cx,10               ;Multiply old lo word by 10
  1469.             mul cx
  1470.             xchg dx,cx              ;CX = new hi word(1)
  1471.             xchg ax,di              ;DI = new lo word
  1472.             mul dx                  ;Multiply old hi word by 10
  1473.             xchg ax,dx              ;DX = new hi word(2)
  1474.             xchg ax,di              ;AX = new lo word
  1475.             add ax,bx               ;Add in digit
  1476.             adc dx,cx               ;DX:AX = new value
  1477.  
  1478. p1_lload:   mov bl,[si]             ;load char
  1479.             inc si
  1480.  
  1481.             cmp bl,'9'              ;Not a digit, finish
  1482.             ja p1_finish
  1483.             sub bl,'0'
  1484.             jnc p1_lloop            ;Jump to loop
  1485.  
  1486. p1_finish:  dec bp                  ;Positive, don't negate
  1487.             jl p1_done
  1488.  
  1489.             neg dx                  ;Negate the result
  1490.             neg ax
  1491.             sbb dx,0
  1492.  
  1493. p1_done:    pop bp di si cx bx      ;Restore registers
  1494.             pop bp                  ;Delete stack frame
  1495.             ret 2                   ;Return
  1496.  
  1497. EndP        atol
  1498.  
  1499. End
  1500.  
  1501. ~~~C_ITOA
  1502. Ideal
  1503.  
  1504. Public      itoa
  1505.  
  1506. Model Tiny
  1507. CodeSeg
  1508. P186
  1509.  
  1510. ;****************** itoa() -- Convert int to string
  1511. ;void itoa(int n, char *strp);
  1512.  
  1513. n           equ bp+6
  1514. strp        equ bp+4
  1515.  
  1516. Proc        itoa
  1517.  
  1518.             push bp                 ;Set up stack frame
  1519.             mov bp,sp
  1520.             pusha                   ;Save all registers
  1521.  
  1522.             mov ax,[n]              ;AX = n
  1523.             mov di,[strp]           ;DI = string pointer
  1524.  
  1525.             test ax,ax              ;Negative?
  1526.             jge p1_noneg
  1527.             mov [byte di],'-'       ;Store minus sign
  1528.             inc di
  1529.             neg ax                  ;Make it positive
  1530.  
  1531. p1_noneg:   xor cx,cx               ;Zero CX
  1532.             test ax,ax              ;Check for zero
  1533.             jnz p1_nozero
  1534.  
  1535.             push '0'                ;Push a zero
  1536.             inc cx                  ;One digit
  1537.             jmp p1_ploop
  1538.  
  1539. p1_nozero:  mov si,10               ;SI = 10
  1540.  
  1541. p1_dloop:   xor dx,dx               ;Divide by 10
  1542.             div si
  1543.             mov bl,dl               ;Remainder in BL
  1544.             add bl,30h              ;Convert to digit
  1545.             push bx                 ;Push digit
  1546.             inc cx
  1547.             test ax,ax              ;Loop back
  1548.             jnz p1_dloop
  1549.  
  1550. p1_ploop:   pop ax                  ;Pop digit
  1551.             mov [di],al             ;Store digit
  1552.             inc di
  1553.             loop p1_ploop           ;Loop back
  1554.  
  1555.             mov [byte di],0         ;Add the null byte
  1556.  
  1557.             popa                    ;Restore registers
  1558.             pop bp                  ;Delete stack frame
  1559.             ret 4                   ;Return
  1560.  
  1561. EndP        itoa
  1562.  
  1563. End
  1564.  
  1565. ~~~C_LTOA
  1566. Ideal
  1567.  
  1568. Extrn       itoa:near
  1569. Public      ltoa
  1570.  
  1571. Model Tiny
  1572. CodeSeg
  1573. P186
  1574.  
  1575. ;****************** ltoa() -- Convert long to string
  1576. ;void ltoa(long n, char *strp);
  1577.  
  1578. n           equ bp+6
  1579. strp        equ bp+4
  1580.  
  1581. Proc        ltoa
  1582.  
  1583.             push bp                 ;Set up stack frame
  1584.             mov bp,sp
  1585.             pusha                   ;Save all registers
  1586.  
  1587.             mov di,[strp]           ;DI = string pointer
  1588.             mov dx,[n+2]            ;DX:AX = n
  1589.             mov ax,[n]
  1590.             test dx,dx              ;DX = 0, use itoa
  1591.             jnz p1_chkn
  1592.             cmp ax,8000h
  1593.             jnb p1_chkn
  1594.  
  1595. p1_itoa:    push ax di              ;Convert with itoa
  1596.             call itoa
  1597.             jmp p1_done             ;Return
  1598.  
  1599. p1_chkn:    cmp dx,-1               ;DX = -1 and AX <> 0, use itoa
  1600.             jne p1_strp
  1601.             cmp ax,8000h
  1602.             jae p1_itoa
  1603.  
  1604. p1_strp:    test dx,dx              ;Negative?
  1605.             jge p1_noneg
  1606.             mov [byte di],'-'       ;Store minus sign
  1607.             inc di
  1608.             neg dx                  ;Make it positive
  1609.             neg ax
  1610.             sbb dx,0
  1611.  
  1612. p1_noneg:   mov bx,50000            ;Divide by 100000
  1613.             div bx
  1614.             xor bx,bx               ;Zero BX
  1615.             shr ax,1
  1616.             adc bx,0                ;BX = rem flag
  1617.             push bx dx              ;Save BX, DX
  1618.  
  1619.             test ax,ax              ;Check for zero
  1620.             jz p1_cont
  1621.  
  1622.             xor cx,cx               ;Zero CX
  1623.             mov si,10               ;SI = 10
  1624.  
  1625. p1_dloop:   xor dx,dx               ;Divide by 10
  1626.             div si
  1627.             mov bl,dl               ;Remainder in BL
  1628.             add bl,30h              ;Convert to digit
  1629.             push bx                 ;Push digit
  1630.             inc cx
  1631.             test ax,ax              ;Loop back
  1632.             jnz p1_dloop
  1633.  
  1634. p1_ploop:   pop ax                  ;Pop digit
  1635.             mov [di],al             ;Store digit
  1636.             inc di
  1637.             loop p1_ploop           ;Loop back
  1638.  
  1639. p1_cont:    pop ax bx               ;Restore low data
  1640.             xor dx,dx               ;Zero DX
  1641.             test bx,bx              ;Check for high part
  1642.             jz p1_nohigh
  1643.  
  1644.             add ax,50000            ;Add in 50000
  1645.             adc dx,0
  1646.  
  1647. p1_nohigh:  mov si,10               ;SI = 10
  1648.             mov cx,5                ;5 digits
  1649.             jmp p1_skip1
  1650.  
  1651. p1_dloopb:  xor dx,dx               ;Zero DX
  1652. p1_skip1:   div si                  ;Divide by 10
  1653.             mov bl,dl               ;Remainder in BL
  1654.             add bl,30h              ;Convert to digit
  1655.             push bx                 ;Push digit
  1656.             loop p1_dloopb          ;Loop back
  1657.  
  1658.             mov cx,5                ;5 digits
  1659.  
  1660. p1_ploopb:  pop ax                  ;Pop digit
  1661.             mov [di],al             ;Store digit
  1662.             inc di
  1663.             loop p1_ploopb          ;Loop back
  1664.  
  1665.             mov [byte di],0         ;Add the null byte
  1666.  
  1667. p1_done:    popa                    ;Restore registers
  1668.             pop bp                  ;Delete stack frame
  1669.             ret 6                   ;Return
  1670.  
  1671. EndP        ltoa
  1672.  
  1673. End
  1674.  
  1675. ~~~C_PUTS
  1676. Ideal
  1677.  
  1678. Public      puts,xputs
  1679.  
  1680. Model Tiny
  1681. CodeSeg
  1682. P186
  1683.  
  1684. ;****************** puts() -- Print string
  1685. ;void puts(char *strp);
  1686.  
  1687. strp        equ bp+4
  1688.  
  1689. Proc        puts
  1690.  
  1691.             push bp                 ;Set up stack frame
  1692.             mov bp,sp
  1693.             pusha                   ;Save all registers
  1694.  
  1695.             mov si,[strp]           ;SI = string pointer
  1696.  
  1697. p1_loop:    lodsb                   ;Get char
  1698.             test al,al              ;Check for null
  1699.             jz p1_done
  1700.             int 29h                 ;Output char
  1701.             jmp p1_loop             ;Loop back
  1702.  
  1703. p1_done:    popa                    ;Restore registers
  1704.             pop bp                  ;Delete stack frame
  1705.             ret 2                   ;Return
  1706.  
  1707. EndP        puts
  1708.  
  1709. ;****************** xputs() -- Print string, generalized
  1710. ;void xputs(void *func, int strp);
  1711.  
  1712. func        equ bp+6
  1713. strp        equ bp+4
  1714.  
  1715. Proc        xputs
  1716.  
  1717.             push bp                 ;Set up stack frame
  1718.             mov bp,sp
  1719.             pusha                   ;Save all registers
  1720.  
  1721.             mov si,[strp]           ;SI = string pointer
  1722.             mov bx,[func]           ;BX = function
  1723.  
  1724. p2_loop:    lodsb                   ;Get char
  1725.             test al,al              ;Check for null
  1726.             jz p2_done
  1727.             push ax                 ;Output char
  1728.             call bx
  1729.             jmp p2_loop             ;Loop back
  1730.  
  1731. p2_done:    popa                    ;Restore registers
  1732.             pop bp                  ;Delete stack frame
  1733.             ret 4                   ;Return
  1734.  
  1735. EndP        xputs
  1736.  
  1737. End
  1738.  
  1739. ~~~C_FPUTS
  1740. Ideal
  1741.  
  1742. Extrn       fputc:near
  1743. Public      fputs
  1744.  
  1745. Model Tiny
  1746. CodeSeg
  1747. P186
  1748.  
  1749. ;****************** fputs() -- Print string to file
  1750. ;int fputs(int fp, char *strp);
  1751.  
  1752. fp          equ bp+6
  1753. strp        equ bp+4
  1754.  
  1755. Proc        fputs
  1756.  
  1757.             push bp                 ;Set up stack frame
  1758.             mov bp,sp
  1759.             push bx si              ;Save registers
  1760.  
  1761.             mov si,[strp]           ;SI = string pointer
  1762.             mov bx,[fp]             ;BX = file pointer
  1763.  
  1764. p1_loop:    lodsb                   ;Get char
  1765.             test al,al              ;Check for null
  1766.             jz p1_done
  1767.             push bx ax              ;Output char:
  1768.             call fputc              ;fputc(fp, AX);
  1769.             test ax,ax
  1770.             jnl p1_loop             ;Loop back
  1771.  
  1772. p1_done:    pop si bx               ;Restore registers
  1773.             pop bp                  ;Delete stack frame
  1774.             ret 4                   ;Return
  1775.  
  1776. EndP        fputs
  1777.  
  1778. End
  1779.  
  1780. ~~~C_GETS
  1781. Ideal
  1782.  
  1783. Public      gets,xgets
  1784.  
  1785. Model Tiny
  1786. CodeSeg
  1787. P186
  1788.  
  1789. ;****************** gets() -- Get string
  1790. ;void gets(char *strp, int max);
  1791.  
  1792. strp        equ bp+6
  1793. max         equ bp+4
  1794.  
  1795. Proc        gets
  1796.  
  1797.             push bp                 ;Set up stack frame
  1798.             mov bp,sp
  1799.             pusha                   ;Save all registers
  1800.             push es
  1801.  
  1802.             mov di,[strp]           ;DI = string pointer
  1803.             mov cx,[max]            ;CX = max string length
  1804.             dec cx
  1805.  
  1806. p1_loop:    xor ax,ax               ;Get key
  1807.             int 16h
  1808.             test al,al              ;Ignore extended keys
  1809.             jz p1_loop
  1810.             cmp al,8                ;Backspace?
  1811.             je p1_bksp
  1812.  
  1813.             int 29h                 ;Show char
  1814.             cmp al,13               ;<Enter> = done
  1815.             je p1_done
  1816.             jcxz p1_loop            ;Maxed out, don't store
  1817.             mov [di],al             ;Store char
  1818.             inc di
  1819.             dec cx                  ;Decrement maximum
  1820.             jmp p1_loop             ;Loop back
  1821.  
  1822. p1_bksp:    cmp di,[strp]           ;At beginning, do nothing
  1823.             je p1_loop
  1824.             dec di                  ;Decrement string pointer
  1825.             inc cx                  ;Increment maximum
  1826.  
  1827.             push cx                 ;Save CX
  1828.             mov ah,0Fh              ;Get video page
  1829.             int 10h
  1830.             mov ah,3                ;Get cursor position
  1831.             int 10h                 ;in DH/DL
  1832.             dec dx                  ;Move left one column
  1833.             test dl,dl              ;if at zero moves up too
  1834.             jnl p1_nowrap
  1835.  
  1836.             push 0                  ;DL = last column
  1837.             pop es
  1838.             mov dl,[es:044Ah]
  1839.             dec dx
  1840.  
  1841. p1_nowrap:  mov ah,2                ;Set cursor position
  1842.             int 10h
  1843.             mov ax,0A20h            ;Clear char at current
  1844.             mov cx,1                ;cursor position
  1845.             int 10h
  1846.             pop cx                  ;Restore CX
  1847.             jmp p1_loop             ;Loop back
  1848.  
  1849. p1_done:    mov al,10               ;Output LF
  1850.             int 29h
  1851.             mov [byte di],0         ;Terminate string
  1852.             pop es                  ;Restore registers
  1853.             popa
  1854.             pop bp                  ;Delete stack frame
  1855.             ret 4                   ;Return
  1856.  
  1857. EndP        gets
  1858.  
  1859. ;****************** xgets() -- Get string, generalized
  1860. ;void xgets(void *func, char *strp, int max, int term);
  1861.  
  1862. strp        equ bp+10
  1863. func        equ bp+8
  1864. max         equ bp+6
  1865. term        equ bp+4
  1866.  
  1867. Proc        xgets
  1868.  
  1869.             push bp                 ;Set up stack frame
  1870.             mov bp,sp
  1871.             pusha                   ;Save all registers
  1872.  
  1873.             mov di,[strp]           ;DI = string pointer
  1874.             mov bx,[func]           ;BX = function
  1875.             mov cx,[max]            ;CX = max string length
  1876.             dec cx
  1877.             mov dx,[term]           ;DX = terminator
  1878.  
  1879. p2_loop:    call bx                 ;Get char
  1880.             cmp al,dl               ;Check for terminator
  1881.             je p2_done
  1882.             jcxz p1_loop            ;Maxed out, don't store
  1883.             mov [di],al             ;Store char
  1884.             inc di
  1885.             dec cx                  ;Decrement maximum
  1886.             jmp p2_loop             ;Loop back
  1887.  
  1888. p2_done:    mov [byte di],0         ;Terminate string
  1889.             popa                    ;Restore registers
  1890.             pop bp                  ;Delete stack frame
  1891.             ret 8                   ;Return
  1892.  
  1893. EndP        xgets
  1894.  
  1895. End
  1896.  
  1897. ~~~C_FGETS
  1898. Ideal
  1899.  
  1900. Extrn       fgetc:near
  1901. Public      fgets
  1902.  
  1903. Model Tiny
  1904. CodeSeg
  1905. P186
  1906.  
  1907. ;****************** fgets() -- Get string from file
  1908. ;void fgets(int fp, char *strp, int max);
  1909.  
  1910. fp          equ bp+8
  1911. strp        equ bp+6
  1912. max         equ bp+4
  1913.  
  1914. Proc        fgets
  1915.  
  1916.             push bp                 ;Set up stack frame
  1917.             mov bp,sp
  1918.             pusha                   ;Save all registers
  1919.  
  1920.             mov di,[strp]           ;DI = string pointer
  1921.             mov bx,[fp]             ;BX = file pointer
  1922.             mov cx,[max]            ;CX = max string length
  1923.             dec cx
  1924.  
  1925. p1_loop:    push bx                 ;Get char
  1926.             call fgetc
  1927.             cmp al,13               ;CR = done
  1928.             je p1_done
  1929.             jcxz p1_loop            ;Maxed out, don't store
  1930.             mov [di],al             ;Store char
  1931.             inc di
  1932.             dec cx                  ;Decrement maximum
  1933.             jmp p1_loop             ;Loop back
  1934.  
  1935. p1_done:    call fgetc              ;Remove LF
  1936.             mov [byte di],0         ;Terminate string
  1937.             popa                    ;Restore registers
  1938.             pop bp                  ;Delete stack frame
  1939.             ret 6                   ;Return
  1940.  
  1941. EndP        fgets
  1942.  
  1943. End
  1944.  
  1945. ~~~C_PRTBUF
  1946. Ideal
  1947.  
  1948. Public      PRT_BUF
  1949.  
  1950. Model Tiny
  1951. CodeSeg
  1952. P186
  1953.  
  1954. ;****************** PRT_BUF -- String buffer for printf(), etc.
  1955.  
  1956. PRT_BUF     db 20 dup(0)
  1957.  
  1958. End
  1959.  
  1960. ~~~C_PRINTF
  1961. Ideal
  1962.  
  1963. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  1964. Public      printf
  1965.  
  1966. Model Tiny
  1967. CodeSeg
  1968. P186
  1969.  
  1970. ;****************** printf() -- Print formatted string
  1971. ;void printf(char *fmt, void *args);
  1972.  
  1973. fmt         equ bp+6
  1974. args        equ bp+4
  1975.  
  1976. Proc        printf
  1977.  
  1978.             push bp                 ;Set up stack frame
  1979.             mov bp,sp
  1980.             pusha                   ;Save all registers
  1981.  
  1982.             mov si,[fmt]            ;SI = string pointer
  1983.             mov bx,[args]           ;BX = arg pointer
  1984.  
  1985. p1_loop:    lodsb                   ;Get char
  1986.             test al,al              ;Check for null
  1987.             jz p1_done
  1988.             cmp al,'%'              ;Check for '%'
  1989.             je p1_proc
  1990. p1_putc:    int 29h                 ;Output char
  1991.             jmp p1_loop             ;Loop back
  1992.  
  1993. p1_proc:    lodsb                   ;Get char
  1994.             test al,al              ;Check for null
  1995.             jz p1_done
  1996.             cmp al,'%'              ; %% = percent
  1997.             je p1_putc
  1998.             cmp al,'d'              ; %d = integer
  1999.             je p1_int
  2000.             cmp al,'l'              ; %l = long int
  2001.             je p1_long
  2002.             cmp al,'x'              ; %x = hex
  2003.             je p1_hex
  2004.             cmp al,'c'              ; %c = char
  2005.             je p1_char
  2006.             cmp al,'s'              ; %s = string
  2007.             je p1_str
  2008.             jmp p1_loop             ;Invalid, ignore
  2009.  
  2010. p1_done:    popa                    ;Restore registers
  2011.             pop bp                  ;Delete stack frame
  2012.             ret 4                   ;Return
  2013.  
  2014. p1_long:    lodsb                   ;Get char
  2015.             test al,al              ;Check for null
  2016.             jz p1_done
  2017.             cmp al,'d'              ; %ld = long integer
  2018.             je p1_lint
  2019.             cmp al,'x'              ; %lx = long hex
  2020.             je p1_lhex
  2021.             jmp p1_loop             ;Invalid, ignore
  2022.  
  2023. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2024.             push offset PRT_BUF
  2025.             call itoa
  2026.             inc bx                  ;Advance pointer
  2027.             inc bx
  2028.             mov di,offset PRT_BUF   ;Print alpha string
  2029.             jmp p1_alpha
  2030.  
  2031. p1_lint:    push [word bx+2]
  2032.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2033.             push offset PRT_BUF
  2034.             call ltoa
  2035.             add bx,4                ;Advance pointer
  2036.             mov di,offset PRT_BUF   ;Print alpha string
  2037.             jmp p1_alpha
  2038.  
  2039. p1_hex:     mov ax,[bx]             ;AX = arg
  2040.             call p1_chex            ;Convert to hex
  2041.             inc bx                  ;Advance pointer
  2042.             inc bx
  2043.             jmp p1_loop             ;Loop back
  2044.  
  2045. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2046.             call p1_chex            ;Convert to hex
  2047.             mov ax,[bx]             ;AX = low word
  2048.             call p1_chex            ;Convert to hex
  2049.             add bx,4                ;Advance pointer
  2050.             jmp p1_loop             ;Loop back
  2051.  
  2052. p1_char:    mov al,[bx]             ;Output char
  2053.             int 29h
  2054.             inc bx                  ;Advance pointer
  2055.             jmp p1_loop             ;Loop back
  2056.  
  2057. p1_str:     mov al,[bx]             ;Get char
  2058.             inc bx                  ;Advance pointer
  2059.             test al,al              ;Check for null
  2060.             jz p1_sdone
  2061.             int 29h                 ;Output char
  2062.             jmp p1_str              ;Loop back
  2063.  
  2064. p1_sdone:   jmp p1_loop             ;Return to main loop
  2065.  
  2066. p1_alpha:   mov al,[di]             ;Get char
  2067.             test al,al              ;Check for null
  2068.             jz p1_sdone
  2069.             int 29h                 ;Output char
  2070.             inc di                  ;Advance pointer
  2071.             jmp p1_alpha            ;Loop back
  2072.  
  2073. p1_chex:    mov cx,4                ;4 hex digits
  2074.             xchg al,ah              ;Reverse the order
  2075.             ror ah,cl               ;of the hex digits
  2076.             ror al,cl               ;in AX
  2077.  
  2078. p1_hloop:   push ax                 ;Save AX
  2079.             and al,0Fh              ;Keep 4 bits
  2080.             cmp al,0Ah              ;Compute the hex digit,
  2081.             sbb al,69h              ;using Improved Allison's Algorithm
  2082.             das
  2083.             int 29h                 ;Output char
  2084.             pop ax                  ;Restore AX
  2085.             shr ax,4                ;Shift it over
  2086.             loop p1_hloop           ;Loop back
  2087.             ret                     ;Return
  2088.  
  2089. EndP        printf
  2090.  
  2091. End
  2092.  
  2093. ~~~C_SPRINT
  2094. Ideal
  2095.  
  2096. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2097. Public      sprintf
  2098.  
  2099. Model Tiny
  2100. CodeSeg
  2101. P186
  2102.  
  2103. ;****************** sprintf() -- Print formatted string into string
  2104. ;void sprintf(char *strp, char *fmt, void *args);
  2105.  
  2106. strp        equ bp+8
  2107. fmt         equ bp+6
  2108. args        equ bp+4
  2109.  
  2110. Proc        sprintf
  2111.  
  2112.             push bp                 ;Set up stack frame
  2113.             mov bp,sp
  2114.             pusha                   ;Save all registers
  2115.  
  2116.             mov di,[strp]           ;DI = string pointer
  2117.             mov si,[fmt]            ;SI = format pointer
  2118.             mov bx,[args]           ;BX = arg pointer
  2119.  
  2120. p1_loop:    lodsb                   ;Get char
  2121.             test al,al              ;Check for null
  2122.             jz p1_done
  2123.             cmp al,'%'              ;Check for '%'
  2124.             je p1_proc
  2125. p1_putc:    stosb                   ;Output char
  2126.             jmp p1_loop             ;Loop back
  2127.  
  2128. p1_proc:    lodsb                   ;Get char
  2129.             test al,al              ;Check for null
  2130.             jz p1_done
  2131.             cmp al,'%'              ; %% = percent
  2132.             je p1_putc
  2133.             cmp al,'d'              ; %d = integer
  2134.             je p1_int
  2135.             cmp al,'l'              ; %l = long int
  2136.             je p1_long
  2137.             cmp al,'x'              ; %x = hex
  2138.             je p1_hex
  2139.             cmp al,'c'              ; %c = char
  2140.             je p1_char
  2141.             cmp al,'s'              ; %s = string
  2142.             je p1_str
  2143.             jmp p1_loop             ;Invalid, ignore
  2144.  
  2145. p1_done:    xor al,al               ;Store a null byte
  2146.             stosb
  2147.             popa                    ;Restore registers
  2148.             pop bp                  ;Delete stack frame
  2149.             ret 6                   ;Return
  2150.  
  2151. p1_long:    lodsb                   ;Get char
  2152.             test al,al              ;Check for null
  2153.             jz p1_done
  2154.             cmp al,'d'              ; %ld = long integer
  2155.             je p1_lint
  2156.             cmp al,'x'              ; %lx = long hex
  2157.             je p1_lhex
  2158.             jmp p1_loop             ;Invalid, ignore
  2159.  
  2160. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2161.             push offset PRT_BUF
  2162.             call itoa
  2163.             inc bx                  ;Advance pointer
  2164.             inc bx
  2165.             mov bp,offset PRT_BUF   ;Print alpha string
  2166.             jmp p1_alpha
  2167.  
  2168. p1_lint:    push [word bx+2]
  2169.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2170.             push offset PRT_BUF
  2171.             call ltoa
  2172.             add bx,4                ;Advance pointer
  2173.             mov bp,offset PRT_BUF   ;Print alpha string
  2174.             jmp p1_alpha
  2175.  
  2176. p1_hex:     mov ax,[bx]             ;AX = arg
  2177.             call p1_chex            ;Convert to hex
  2178.             inc bx                  ;Advance pointer
  2179.             inc bx
  2180.             jmp p1_loop             ;Loop back
  2181.  
  2182. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2183.             call p1_chex            ;Convert to hex
  2184.             mov ax,[bx]             ;AX = low word
  2185.             call p1_chex            ;Convert to hex
  2186.             add bx,4                ;Advance pointer
  2187.             jmp p1_loop             ;Loop back
  2188.  
  2189. p1_char:    mov al,[bx]             ;Output char
  2190.             stosb
  2191.             inc bx                  ;Advance pointer
  2192.             jmp p1_loop             ;Loop back
  2193.  
  2194. p1_str:     mov al,[bx]             ;Get char
  2195.             inc bx                  ;Advance pointer
  2196.             test al,al              ;Check for null
  2197.             jz p1_sdone
  2198.             stosb                   ;Output char
  2199.             jmp p1_str              ;Loop back
  2200.  
  2201. p1_sdone:   jmp p1_loop             ;Return to main loop
  2202.  
  2203. p1_alpha:   mov al,[bp]             ;Get char
  2204.             test al,al              ;Check for null
  2205.             jz p1_sdone
  2206.             stosb                   ;Output char
  2207.             inc bp                  ;Advance pointer
  2208.             jmp p1_alpha            ;Loop back
  2209.  
  2210. p1_chex:    mov cx,4                ;4 hex digits
  2211.             xchg al,ah              ;Reverse the order
  2212.             ror ah,cl               ;of the hex digits
  2213.             ror al,cl               ;in AX
  2214.  
  2215. p1_hloop:   push ax                 ;Save AX
  2216.             and al,0Fh              ;Keep 4 bits
  2217.             cmp al,0Ah              ;Compute the hex digit,
  2218.             sbb al,69h              ;using Improved Allison's Algorithm
  2219.             das
  2220.             stosb                   ;Output char
  2221.             pop ax                  ;Restore AX
  2222.             shr ax,4                ;Shift it over
  2223.             loop p1_hloop           ;Loop back
  2224.             ret                     ;Return
  2225.  
  2226. EndP        sprintf
  2227.  
  2228. End
  2229.  
  2230. ~~~C_FPRINT
  2231. Ideal
  2232.  
  2233. Extrn       PRT_BUF:byte,fputc:near,itoa:near,ltoa:near
  2234. Public      fprintf
  2235.  
  2236. Model Tiny
  2237. CodeSeg
  2238. P186
  2239.  
  2240. ;****************** fprintf() -- Print formatted string to file
  2241. ;void fprintf(int fp, char *fmt, void *args);
  2242.  
  2243. fp          equ bp+8
  2244. fmt         equ bp+6
  2245. args        equ bp+4
  2246.  
  2247. Proc        fprintf
  2248.  
  2249.             push bp                 ;Set up stack frame
  2250.             mov bp,sp
  2251.             pusha                   ;Save all registers
  2252.  
  2253.             mov dx,[fp]             ;DX = file pointer
  2254.             mov si,[fmt]            ;SI = string pointer
  2255.             mov bx,[args]           ;BX = arg pointer
  2256.  
  2257. p1_loop:    lodsb                   ;Get char
  2258.             test al,al              ;Check for null
  2259.             jz p1_done
  2260.             cmp al,'%'              ;Check for '%'
  2261.             je p1_proc
  2262. p1_putc:    push dx ax              ;Output char
  2263.             call fputc
  2264.             jmp p1_loop             ;Loop back
  2265.  
  2266. p1_proc:    lodsb                   ;Get char
  2267.             test al,al              ;Check for null
  2268.             jz p1_done
  2269.             cmp al,'%'              ; %% = percent
  2270.             je p1_putc
  2271.             cmp al,'d'              ; %d = integer
  2272.             je p1_int
  2273.             cmp al,'l'              ; %l = long int
  2274.             je p1_long
  2275.             cmp al,'x'              ; %x = hex
  2276.             je p1_hex
  2277.             cmp al,'c'              ; %c = char
  2278.             je p1_char
  2279.             cmp al,'s'              ; %s = string
  2280.             je p1_str
  2281.             jmp p1_loop             ;Invalid, ignore
  2282.  
  2283. p1_done:    popa                    ;Restore registers
  2284.             pop bp                  ;Delete stack frame
  2285.             ret 6                   ;Return
  2286.  
  2287. p1_long:    lodsb                   ;Get char
  2288.             test al,al              ;Check for null
  2289.             jz p1_done
  2290.             cmp al,'d'              ; %ld = long integer
  2291.             je p1_lint
  2292.             cmp al,'x'              ; %lx = long hex
  2293.             je p1_lhex
  2294.             jmp p1_loop             ;Invalid, ignore
  2295.  
  2296. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2297.             push offset PRT_BUF
  2298.             call itoa
  2299.             inc bx                  ;Advance pointer
  2300.             inc bx
  2301.             mov di,offset PRT_BUF   ;Print alpha string
  2302.             jmp p1_alpha
  2303.  
  2304. p1_lint:    push [word bx+2]
  2305.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2306.             push offset PRT_BUF
  2307.             call ltoa
  2308.             add bx,4                ;Advance pointer
  2309.             mov di,offset PRT_BUF   ;Print alpha string
  2310.             jmp p1_alpha
  2311.  
  2312. p1_hex:     mov ax,[bx]             ;AX = arg
  2313.             call p1_chex            ;Convert to hex
  2314.             inc bx                  ;Advance pointer
  2315.             inc bx
  2316.             jmp p1_loop             ;Loop back
  2317.  
  2318. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2319.             call p1_chex            ;Convert to hex
  2320.             mov ax,[bx]             ;AX = low word
  2321.             call p1_chex            ;Convert to hex
  2322.             add bx,4                ;Advance pointer
  2323.             jmp p1_loop             ;Loop back
  2324.  
  2325. p1_char:    mov al,[bx]             ;Output char
  2326.             push dx ax
  2327.             call fputc
  2328.             inc bx                  ;Advance pointer
  2329.             jmp p1_loop             ;Loop back
  2330.  
  2331. p1_str:     mov al,[bx]             ;Get char
  2332.             inc bx                  ;Advance pointer
  2333.             test al,al              ;Check for null
  2334.             jz p1_sdone
  2335.             push dx ax              ;Output char
  2336.             call fputc
  2337.             jmp p1_str              ;Loop back
  2338.  
  2339. p1_sdone:   jmp p1_loop             ;Return to main loop
  2340.  
  2341. p1_alpha:   mov al,[di]             ;Get char
  2342.             test al,al              ;Check for null
  2343.             jz p1_sdone
  2344.             push dx ax              ;Output char
  2345.             call fputc
  2346.             inc di                  ;Advance pointer
  2347.             jmp p1_alpha            ;Loop back
  2348.  
  2349. p1_chex:    mov cx,4                ;4 hex digits
  2350.             xchg al,ah              ;Reverse the order
  2351.             ror ah,cl               ;of the hex digits
  2352.             ror al,cl               ;in AX
  2353.  
  2354. p1_hloop:   push ax                 ;Save AX
  2355.             and al,0Fh              ;Keep 4 bits
  2356.             cmp al,0Ah              ;Compute the hex digit,
  2357.             sbb al,69h              ;using Improved Allison's Algorithm
  2358.             das
  2359.             push dx ax              ;Output char
  2360.             call fputc
  2361.             pop ax                  ;Restore AX
  2362.             shr ax,4                ;Shift it over
  2363.             loop p1_hloop           ;Loop back
  2364.             ret                     ;Return
  2365.  
  2366. EndP        fprintf
  2367.  
  2368. End
  2369.  
  2370. ~~~C_XPRINT
  2371. Ideal
  2372.  
  2373. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2374. Public      xprintf
  2375.  
  2376. Model Tiny
  2377. CodeSeg
  2378. P186
  2379.  
  2380. ;****************** xprintf() -- Print formatted string, generalized
  2381. ;void xprintf(void *func, char *fmt, void *args);
  2382.  
  2383. func        equ bp+8
  2384. fmt         equ bp+6
  2385. args        equ bp+4
  2386.  
  2387. Proc        xprintf
  2388.  
  2389.             push bp                 ;Set up stack frame
  2390.             mov bp,sp
  2391.             pusha                   ;Save all registers
  2392.  
  2393.             mov dx,[func]           ;DX = function pointer
  2394.             mov si,[fmt]            ;SI = string pointer
  2395.             mov bx,[args]           ;BX = arg pointer
  2396.  
  2397. p1_loop:    lodsb                   ;Get char
  2398.             test al,al              ;Check for null
  2399.             jz p1_done
  2400.             cmp al,'%'              ;Check for '%'
  2401.             je p1_proc
  2402. p1_putc:    push ax                 ;Output char
  2403.             call dx
  2404.             jmp p1_loop             ;Loop back
  2405.  
  2406. p1_proc:    lodsb                   ;Get char
  2407.             test al,al              ;Check for null
  2408.             jz p1_done
  2409.             cmp al,'%'              ; %% = percent
  2410.             je p1_putc
  2411.             cmp al,'d'              ; %d = integer
  2412.             je p1_int
  2413.             cmp al,'l'              ; %l = long int
  2414.             je p1_long
  2415.             cmp al,'x'              ; %x = hex
  2416.             je p1_hex
  2417.             cmp al,'c'              ; %c = char
  2418.             je p1_char
  2419.             cmp al,'s'              ; %s = string
  2420.             je p1_str
  2421.             jmp p1_loop             ;Invalid, ignore
  2422.  
  2423. p1_done:    popa                    ;Restore registers
  2424.             pop bp                  ;Delete stack frame
  2425.             ret 6                   ;Return
  2426.  
  2427. p1_long:    lodsb                   ;Get char
  2428.             test al,al              ;Check for null
  2429.             jz p1_done
  2430.             cmp al,'d'              ; %ld = long integer
  2431.             je p1_lint
  2432.             cmp al,'x'              ; %lx = long hex
  2433.             je p1_lhex
  2434.             jmp p1_loop             ;Invalid, ignore
  2435.  
  2436. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2437.             push offset PRT_BUF
  2438.             call itoa
  2439.             inc bx                  ;Advance pointer
  2440.             inc bx
  2441.             mov di,offset PRT_BUF   ;Print alpha string
  2442.             jmp p1_alpha
  2443.  
  2444. p1_lint:    push [word bx+2]
  2445.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2446.             push offset PRT_BUF
  2447.             call ltoa
  2448.             add bx,4                ;Advance pointer
  2449.             mov di,offset PRT_BUF   ;Print alpha string
  2450.             jmp p1_alpha
  2451.  
  2452. p1_hex:     mov ax,[bx]             ;AX = arg
  2453.             call p1_chex            ;Convert to hex
  2454.             inc bx                  ;Advance pointer
  2455.             inc bx
  2456.             jmp p1_loop             ;Loop back
  2457.  
  2458. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2459.             call p1_chex            ;Convert to hex
  2460.             mov ax,[bx]             ;AX = low word
  2461.             call p1_chex            ;Convert to hex
  2462.             add bx,4                ;Advance pointer
  2463.             jmp p1_loop             ;Loop back
  2464.  
  2465. p1_char:    mov al,[bx]             ;Output char
  2466.             push ax
  2467.             call dx
  2468.             inc bx                  ;Advance pointer
  2469.             jmp p1_loop             ;Loop back
  2470.  
  2471. p1_str:     mov al,[bx]             ;Get char
  2472.             inc bx                  ;Advance pointer
  2473.             test al,al              ;Check for null
  2474.             jz p1_sdone
  2475.             push ax                 ;Output char
  2476.             call dx
  2477.             jmp p1_str              ;Loop back
  2478.  
  2479. p1_sdone:   jmp p1_loop             ;Return to main loop
  2480.  
  2481. p1_alpha:   mov al,[di]             ;Get char
  2482.             test al,al              ;Check for null
  2483.             jz p1_sdone
  2484.             push ax                 ;Output char
  2485.             call dx
  2486.             inc di                  ;Advance pointer
  2487.             jmp p1_alpha            ;Loop back
  2488.  
  2489. p1_chex:    mov cx,4                ;4 hex digits
  2490.             xchg al,ah              ;Reverse the order
  2491.             ror ah,cl               ;of the hex digits
  2492.             ror al,cl               ;in AX
  2493.  
  2494. p1_hloop:   push ax                 ;Save AX
  2495.             and al,0Fh              ;Keep 4 bits
  2496.             cmp al,0Ah              ;Compute the hex digit,
  2497.             sbb al,69h              ;using Improved Allison's Algorithm
  2498.             das
  2499.             push ax                 ;Output char
  2500.             call dx
  2501.             pop ax                  ;Restore AX
  2502.             shr ax,4                ;Shift it over
  2503.             loop p1_hloop           ;Loop back
  2504.             ret                     ;Return
  2505.  
  2506. EndP        xprintf
  2507.  
  2508. End
  2509.  
  2510. ~~~C_CPULVL
  2511. Ideal
  2512.  
  2513. Public      cputype
  2514.  
  2515. Model Tiny
  2516. P186
  2517. CodeSeg
  2518.  
  2519. ;**************************** cputype() -- Returns CPU level
  2520. ;int cputype(void);
  2521.  
  2522. Proc        cputype
  2523.  
  2524.             push es            ;Save ES
  2525.             pusha              ;Save gen. regs
  2526.             
  2527.             call p1_getcpu     ;Call main procedure
  2528.  
  2529.             shr ax,8           ;AL = AH, AH = 0
  2530.             mov es,ax          ;ES = AX
  2531.             popa               ;Restore gen. regs
  2532.             mov ax,es          ;Return value in AX
  2533.             pop es             ;Restore ES
  2534.             ret                ;Return
  2535.             
  2536.             
  2537. p1_getcpu:  mov al,1           ;If AL can be shifted
  2538.             mov cl,21h         ;by 21h, then it's an
  2539.             shl al,cl          ;8086, because a 186+
  2540.             jz p1_8086         ;limits shift counts.
  2541.  
  2542.             push sp            ;If SP is pushed as its
  2543.             pop ax             ;original value, then
  2544.             cmp ax,sp          ;it's a 286+.
  2545.             jne p1_186
  2546.  
  2547.             pushf              ;Save flags
  2548.             cli                ;No interrupts
  2549.             pushf              ;AX = flags
  2550.             pop ax
  2551.             mov bx,ax          ;BX = flags
  2552.             xor ax,7000h       ;Toggle IOPL bit
  2553.             push ax            ;Flags = AX
  2554.             popf
  2555.             pushf              ;AX = flags
  2556.             pop ax
  2557.             popf               ;Restore flags
  2558.             cmp ax,bx          ;If the bit was not
  2559.             je p1_286          ;reset, it's a 386+
  2560. P386
  2561.             push bp            ;Align stack to dword
  2562.             mov bp,sp
  2563.             and sp,0FFFCh
  2564.             pushfd             ;Save eflags
  2565.             cli                ;No interrupts
  2566.             pushfd             ;EAX = eflags
  2567.             pop eax
  2568.             mov ebx,eax        ;EBX = eflags
  2569.             xor eax,40000h     ;Toggle AC bit
  2570.             push eax           ;Eflags = EAX
  2571.             popfd
  2572.             pushfd             ;EAX = eflags
  2573.             pop eax
  2574.             popfd              ;Restore eflags
  2575.             mov sp,bp          ;Restore stack
  2576.             pop bp
  2577.             cmp eax,ebx        ;If the bit was not
  2578.             je p1_386          ;reset, it's a 486+
  2579.  
  2580.             pushfd             ;Save eflags
  2581.             cli                ;No interrupts
  2582.             pushfd             ;EAX = eflags
  2583.             pop eax
  2584.             mov ebx,eax        ;EBX = eflags
  2585.             xor eax,200000h    ;Toggle ID bit
  2586.             push eax           ;Eflags = EAX
  2587.             popfd
  2588.             pushfd             ;EAX = eflags
  2589.             pop eax
  2590.             popfd              ;Restore eflags
  2591.             cmp eax,ebx        ;If the bit was not
  2592.             je p1_486          ;reset, it's a 586+
  2593. P586
  2594.             xor eax,eax        ;EAX = 1
  2595.             inc ax
  2596.             cpuid              ;Get CPU type
  2597.             ret                ;Return
  2598. P186
  2599. p1_486:     mov ah,4           ;486, return 4
  2600.             ret
  2601.  
  2602. p1_386:     mov ah,3           ;386, return 3
  2603.             ret
  2604.  
  2605. p1_286:     mov ah,2           ;286, return 2
  2606.             ret
  2607.  
  2608. p1_186:     mov ah,1           ;186, return 1
  2609.             ret
  2610.  
  2611. p1_8086:    mov ah,0           ;8086, return 0
  2612.             ret
  2613.  
  2614. EndP        cputype
  2615.  
  2616. End
  2617.  
  2618. ~~~C_FPULVL
  2619. Ideal
  2620.  
  2621. Public      fputype
  2622.  
  2623. Model Tiny
  2624. P186
  2625. CodeSeg
  2626.  
  2627. ;**************************** fputype() -- Returns FPU level, init FPU
  2628. ;int fputype(void);                        -1 means no FPU
  2629.  
  2630. Proc        fputype 
  2631.  
  2632.             push es            ;Save ES
  2633.             pusha              ;Save gen. regs
  2634.             
  2635.             call p2_getfpu     ;Get FPU type
  2636.  
  2637.             mov es,ax          ;ES = AX
  2638.             popa               ;Restore gen. regs
  2639.             mov ax,es          ;Return value in AX
  2640.             pop es             ;Restore ES
  2641.             ret                ;Return
  2642. P8087
  2643. p2_getfpu:  fninit             ;Initialize FPU
  2644.             mov [Junk],55AAh   ;Set junk value
  2645.             fnstsw [Junk]      ;Store status word
  2646.             cmp [byte Junk],0  ;If it's not 0, no FPU
  2647.             jne p2_nofpu
  2648.             fnstcw [Junk]      ;Store control word
  2649.             mov ax,[Junk]      ;If the bits are not the way
  2650.             and ax,103Fh       ;they should be, no FPU
  2651.             cmp ax,3Fh
  2652.             jne p2_nofpu
  2653.  
  2654.             and [Junk],0FF7Fh  ;Clear interrupt bit
  2655.             fldcw [Junk]       ;Load control word
  2656.             fdisi              ;Disable interrupts
  2657.             fstcw [Junk]       ;Store control word
  2658.             test [Junk],80h    ;If it changed, it's an 8087
  2659.             jnz p2_8087
  2660. P286
  2661. P287
  2662.             finit              ;Re-initialize
  2663.             fld1               ;Divide 1 by 0 to get
  2664.             fldz               ;a positive infinity
  2665.             fdiv
  2666.             fld st             ;Get a negative infinity
  2667.             fchs
  2668.             fcompp             ;Compare them
  2669.             fstsw ax           ;Store status word
  2670.             sahf               ;If the FPU thought that they
  2671.             je p2_287          ;were equal, it's a 287
  2672.  
  2673.             mov ax,3           ;387, return 3
  2674.             finit              ;Init processor
  2675.             ret
  2676.  
  2677. p2_287:     mov ax,2           ;287, return 2
  2678.             finit              ;Init processor
  2679.             ret
  2680. P186
  2681. P8087
  2682. p2_8087:    xor ax,ax          ;8087, return 0
  2683.             finit              ;Init processor
  2684.             ret
  2685.  
  2686. p2_nofpu:   mov ax,-1          ;No FPU, return -1
  2687.             ret
  2688.  
  2689. Junk        dw 0
  2690.  
  2691. EndP        fputype
  2692.  
  2693. End
  2694.  
  2695. ~~~C_RAND
  2696. Ideal
  2697.  
  2698. Public      rand,srand
  2699.  
  2700. Model Tiny
  2701. P186
  2702. CodeSeg
  2703.  
  2704. RandNum     dw 0,0                  ;Random number
  2705.  
  2706. ;****************** rand() -- Returns a random number below N
  2707. ;int rand(int max);
  2708.  
  2709. max         equ bp+4
  2710.  
  2711. Proc        rand
  2712.  
  2713.             push bp                 ;Set up stack frame
  2714.             mov bp,sp
  2715.             push bx cx dx           ;Save registers
  2716.  
  2717.             mov ax,[RandNum]        ;CX:BX = RandNum * 015A4EC5h
  2718.             mov dx,4EC5h            ;low * low
  2719.             mul dx
  2720.             mov cx,dx               ;put it in CX:BX
  2721.             mov bx,ax
  2722.             imul ax,[RandNum],015Ah ;low * high, high * low
  2723.             imul dx,[RandNum+2],4EC5h
  2724.             add cx,ax               ;add them in
  2725.             add cx,dx
  2726.  
  2727.             add bx,1                ;Increment CX:BX
  2728.             adc cx,1
  2729.  
  2730.             mov [RandNum],bx        ;Save random number
  2731.             mov [RandNum+2],cx
  2732.  
  2733.             mov ax,bx               ;AX = high 14 bits of BX
  2734.             and ax,0FFFCh           ; plus low 2 bits of CX
  2735.             and cx,3
  2736.             or ax,cx
  2737.             mov bx,[max]            ;BX = maximum
  2738.             xor dx,dx               ;Zero DX
  2739.             test bx,bx              ;Can't divide by zero
  2740.             jz p1_skip
  2741.             div bx                  ;Divide by BX
  2742. p1_skip:    mov ax,dx               ;Result in AX
  2743.  
  2744.             pop dx cx bx            ;Restore registers
  2745.             pop bp                  ;Delete stack frame
  2746.             ret 2                   ;Return
  2747.  
  2748. EndP        rand
  2749.  
  2750. ;****************** srand() -- Seeds the RNG with the time
  2751. ;void srand(void);
  2752.  
  2753. Proc        srand
  2754.  
  2755.             push bp                 ;Set up stack frame
  2756.             mov bp,sp
  2757.             push ax es              ;Save registers
  2758.  
  2759.             push 40h                ;ES = BIOS segment
  2760.             pop es
  2761.  
  2762.             mov ax,[es:6Ch]         ;Get low word
  2763.             mov [RandNum],ax        ;Save it
  2764.             mov ax,[es:6Eh]         ;Get high word
  2765.             mov [RandNum+2],ax      ;Save it
  2766.  
  2767.             pop es ax               ;Restore registers
  2768.             popa
  2769.             ret                     ;Return
  2770.  
  2771. EndP        srand
  2772.  
  2773. End
  2774.  
  2775. ~~~C_DELAY
  2776. Ideal
  2777.  
  2778. Public      delay
  2779.  
  2780. Model Tiny
  2781. P186
  2782. CodeSeg
  2783.  
  2784. ;****************** delay() -- Delay in milliseconds
  2785. ;void delay(int dtime);
  2786.  
  2787. dtime       equ bp+4
  2788.  
  2789. Proc        delay
  2790.  
  2791.             push bp                 ;Set up stack frame
  2792.             mov bp,sp
  2793.             pusha                   ;Save registers
  2794.  
  2795.             mov ax,[dtime]          ;AX = time in milliseconds
  2796.             mov dx,1000             ;Multiply by 1000
  2797.             mul dx                  ;DX:AX = time in microseconds
  2798.  
  2799.             mov cx,dx               ;CX:DX = time
  2800.             mov dx,ax
  2801.             mov ah,86h              ;BIOS Delay Service
  2802.             int 15h
  2803.  
  2804.             popa                    ;Restore registers
  2805.             pop bp                  ;Delete stack frame
  2806.             ret 2                   ;Return
  2807.  
  2808. EndP        delay
  2809.  
  2810. End
  2811.  
  2812. ~~~C_SOUND
  2813. Ideal
  2814.  
  2815. Public      sound,nosound
  2816.  
  2817. Model Tiny
  2818. P186
  2819. CodeSeg
  2820.  
  2821. ;****************** sound() -- Turn on speaker at specific frequency
  2822. ;void sound(int freq);
  2823.  
  2824. freq        equ bp+4
  2825.  
  2826. Proc        sound
  2827.  
  2828.             push bp                 ;Set up stack frame
  2829.             mov bp,sp
  2830.             pusha                   ;Save registers
  2831.  
  2832.             mov dx,12h              ;BX = 1193180 / freq.
  2833.             mov ax,34DCh
  2834.             mov bx,[freq]
  2835.             div bx
  2836.             mov bx,ax
  2837.  
  2838.             mov al,0B6h             ;Set frequency
  2839.             out 43h,al
  2840.             mov al,bl
  2841.             out 42h,al
  2842.             mov al,bh
  2843.             out 42h,al
  2844.  
  2845.             in al,61h               ;Turn on speaker
  2846.             or al,3
  2847.             out 61h,al
  2848.  
  2849.             popa                    ;Restore registers
  2850.             pop bp                  ;Delete stack frame
  2851.             ret 2                   ;Return
  2852.  
  2853. EndP        sound
  2854.  
  2855. ;****************** nosound() -- Turn off speaker
  2856. ;void nosound(void);
  2857.  
  2858. Proc        nosound
  2859.  
  2860.             push bp                 ;Set up stack frame
  2861.             mov bp,sp
  2862.             push ax                 ;Save AX
  2863.  
  2864.             in al,61h               ;Turn off speaker
  2865.             and al,0FCh
  2866.             out 61h,al
  2867.  
  2868.             pop ax                  ;Restore AX
  2869.             ret                     ;Return
  2870.  
  2871. EndP        nosound
  2872.  
  2873. End
  2874.